1時間プログラミング 007 Github GraphQL APIで指定した日付のコミットを取得する
概要
所要時間: 2時間
使い方
deno run --allow-net --allow-env mod.ts [YYYY-MM-DD]
引数の省略時は、今日の日付が指定されたものとする
code:terminal
$ GH_COMMITS_AUTH_TOKEN=XXX GH_COMMITS_EMAIL=XXX deno run --allow-net --allow-env mod.ts
日記にペーストしたいので、Scrapboxの箇条書き形式で出力している 実装
オブジェクトの構造が複雑なので、他の人の例を参考にする
code:graphql
query($login: String!, $email: String!, $from: DateTime!, $to: DateTime!, $commitSince: GitTimestamp!, $commitUntil: GitTimestamp!) {
user(login: $login) {
contributionsCollection(from: $from, to: $to) {
commitContributionsByRepository {
repository {
name,
url,
refs(refPrefix: "refs/heads/", first: 100) {
nodes {
name,
target {
... on Commit {
history(
first: 100,
since: $commitSince,
until: $commitUntil,
) {
nodes {
message,
commitUrl,
}
}
}
}
}
}
}
}
}
}
}
プログラムはTS(Deno)で作る
リクエストのサンプル
code:mod.ts
const request = async <T>(token: string, query: string, variables: {key:string: any } = {}): Promise<T> => { const resp = await fetch(url, {
method: 'POST',
headers: {
'Authorization': bearer ${token},
},
body: JSON.stringify({ query, variables }),
});
return (await resp.json()).data;
};
// ログインユーザー名を取得するサンプル
const fetchLoginUsername = async (
token: string,
): Promise<string> => {
const query = `
query {
viewer {
login
}
}
`;
const res = await request<{ viewer: { login: string } }>(token, query);
return res.viewer.login;
};
DateTimeのライブラリはpteraを使用した code:ts
const now = datetime();
const startOfDay = now.startOfDay();
const endOfDay = now.endOfDay();
指定した日付のコミットを取得する
code:ts
type CommitsByRepository = {
name: string;
url: string;
branches: {
name: string;
commits: {
message: string;
commitUrl: string;
}[];
}[];
};
const fetchCommits = async (
params: {
token: string;
login: string;
email: string;
startOfDay: string;
endOfDay: string;
},
): Promise<CommitsByRepository[]> => {
const {
token,
login,
email,
startOfDay,
endOfDay,
} = params;
const query = 省略;
const variables = {
login,
email,
from: startOfDay,
to: endOfDay,
commitSince: startOfDay,
commitUntil: endOfDay,
};
// TODO: 型パラメータを指定する
const res = await request<any>(token, query, variables);
return res.user.contributionsCollection.commitContributionsByRepository.map(
({ repository }: { repository: any }) => {
return {
name: repository.name,
url: repository.url,
branches: repository.refs.nodes.map((b: any) => {
return {
name: b.name,
commits: b.target.history.nodes,
};
}),
};
},
);
};
出力形式はScrapboxの箇条書きにする
code:ts
const printCommits = (repoCommits: CommitsByRepository[]): void => {
// Scrapbox format
repoCommits.forEach((repo) => {
const outputCommits = repo.branches.flatMap((b) => {
const branchName = b.name;
const branchLabel = (branchName === "main" || branchName === "master")
? ""
: ${branchName}:;
return b.commits.map((c) => {
return ${branchLabel}[${c.message} ${c.commitUrl}];
});
});
if (outputCommits.length === 0) return;
console.log( [${repo.name} ${repo.url}] ${outputCommits.length}commits);
console.log(outputCommits.join("\n"));
});
};
感想
GraphQL APIを初めて使用したが、便利〜って感じ
最近は1時間を越えているので、次はもっと簡単なお題にしたい